package com.yeyks.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yeyks.apppay.service.AlipayService;
import com.yeyks.apppay.service.WXAppPayService;
import com.yeyks.base.PageInfo;
import com.yeyks.constant.ConfigKey;
import com.yeyks.constant.MessageTemplate;
import com.yeyks.dal.dao.RechargeRecordMapper;
import com.yeyks.dal.domain.*;
import com.yeyks.dto.PayParam;
import com.yeyks.dto.RecommendDetailDTO;
import com.yeyks.exception.ServiceException;
import com.yeyks.model.CouponConst;
import com.yeyks.model.em.RechargeRecordStatus;
import com.yeyks.model.enums.PayTypeEnum;
import com.yeyks.model.enums.RechangeRecordEnum;
import com.yeyks.service.*;
import com.yeyks.util.FormatUtils;
import com.yeyks.util.ObjectConvertUtil;
import com.yeyks.util.Splitters;
import com.yeyks.util.Utility;
import com.yeyks.util.arithmetic.Lottery;
import com.yeyks.util.arithmetic.Probability;
import com.yeyks.wxcode.dto.WxPayParam;
import com.yeyks.wxcode.service.WxLoginService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author fuchangshuai
 * @date 2019/4/23 0023
 */
@Service
@Slf4j
public class RechargeRecordServiceImpl implements RechargeRecordService {

    @Autowired
    private RechargeRecordMapper rechargeRecordMapper;
    @Autowired
    private UserInfoService userInfoService;
    @Autowired
    private ConfigService configService;
    @Autowired
    private UserAccountOverviewService overviewService;
    @Autowired
    private UserCouponService userCouponService;
    @Autowired
    private AlipayService alipayService;
    @Autowired
    private WXAppPayService wxAppPayService;
    @Autowired
    private MessageNoticeService noticeService;
    @Autowired
    private MessageNoticeTemplateService templateService;
    @Autowired
    private WxLoginService wxLoginService;
    @Value("${wx.app.rechangeNotifyUrl}")
    String rechange_notify_url;

    @Override
    public Map<String, Object> h5Pay(PayParam payParam) {
        RechargeRecord rechargeRecord = getRechargeRecord(payParam);
        WxPayMpOrderResult wxPayInfo;
        WxPayParam wxPayParam = getWxPayParam(payParam, rechargeRecord.getOrderNo(), "JSAPI");
        try {
            wxPayInfo = wxLoginService.unifiedOrder(wxPayParam);
        } catch (Exception e) {
            log.info("微信JSAPI支付异常{}", Arrays.toString(e.getStackTrace()));
            throw new ServiceException("支付异常");
        }
        rechargeRecordMapper.insert(rechargeRecord);
        Map<String, Object> map = new HashMap<>();
        map.put("orderNo", rechargeRecord.getOrderNo());
        map.put("payInfo", wxPayInfo);
        return map;

    }

    private WxPayParam getWxPayParam(PayParam payParam, String orderNo, String tradeType) {
        return new WxPayParam(payParam.getType(), payParam.getOpenId(), "商品描述",
                payParam.getPrice(), orderNo, payParam.getIp(), rechange_notify_url, tradeType);
    }

    /**
     * 处理推广充值回调
     *
     * @param orderNo 订单号
     * @param flag    是否成功
     */
    @Override
    @Transactional
    public void payCallback(String orderNo, Boolean flag) {
        //通过订单号查询订单
        RechargeRecord rechargeRecord = rechargeRecordMapper.selectOrderByOrderNo(orderNo);
        int status = RechargeRecordStatus.postPay;
        //成功，并发放佣金
        if (flag) {
            //发放佣金
            Map<String, String> map = commission(rechargeRecord);
            //发放券
            sendCouponInfo(rechargeRecord);
            //写入佣金消息
            commissionMessage(map, rechargeRecord.getPayAmount());
        } else {
            status = RechargeRecordStatus.payFailed;
        }
        //修改订单的状态
        Integer res = rechargeRecordMapper.updateByOrderNoAndStatus(orderNo, status);
        if (res != 1) {
            log.info("充值更新订单状态失败");
        }
    }

    /**
     * 通过推广订单id获取推广订单信息
     *
     * @param orderNo
     * @return
     */
    @Override
    public RechargeRecord selectOrderByOrderNo(String orderNo) {
        return rechargeRecordMapper.selectOrderByOrderNo(orderNo);
    }

    /**
     * 通过邀请码获取该邀请码对应推广人数
     *
     * @param inviteCode
     * @return
     */
    @Override
    public Integer selectCountByInviteId(String inviteCode) {
        return rechargeRecordMapper.selectCountByInviteId(inviteCode);
    }

    /**
     * 获取佣金明细
     *
     * @param userId
     * @param type
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    public List<RecommendDetailDTO> detailList(Integer userId, String type, Integer pageNo, Integer pageSize) {
        List<RecommendDetailDTO> recommendDetailDTOS = new ArrayList<>();
        try {
            PageInfo pageInfo = PageInfo.of(pageNo, pageSize);
            Map<String, Object> param = new HashMap<>();
            param.put("userId", userId);
            param.put("type", type);
            param.put("offset", pageInfo.getOffset());
            param.put("limit", pageInfo.getLimit());
            List<MessageNotice> lists = noticeService.detailList(param);
            if (lists == null) {
                return recommendDetailDTOS;
            }
            recommendDetailDTOS = ObjectConvertUtil.convertList(lists, RecommendDetailDTO.class);
        } catch (Exception e) {
            log.error("分页获取佣金明细通知消息失败{}", e.getLocalizedMessage());
            e.printStackTrace();
        }
        return recommendDetailDTOS;
    }

    /**
     * 推广规则
     *
     * @return
     */
    @Override
    public List<String> rule() {
        List<String> lists = Lists.newArrayList();
        try {
            String value = configService.getValue(ConfigKey.RECOMMEND_RULE);
            log.info(value);
            lists = Splitters.splitToString(value, Splitters.ENTER);
            return lists;

        } catch (Exception e) {
            lists.add("1. 推广期间，长按保存二维码分享给好友或者直接邀请好友直接扫描二维码即可参与活动");
            lists.add("2. 好友进入推广活动，输入手机号支付10元完成参与活动");
            lists.add("3. 好友支付十元，用户即可获得7元佣金，同时好友获得一张30元及以上优惠券一张或免单券一张");
            lists.add("4. 用户获得的佣金支持绑定银行卡提现");
            lists.add("5. 好友获得优惠券可在预订酒店时使用");
            lists.add("6. 若有疑问请拨打客服热线：400-8263595 客服时间：9：00 - 17:00");
            lists.add("7. 夜鱼快宿保留该活动最终解释权");
        }
        return null;
    }

    /**
     * app用户推广充值
     *
     * @param payParam
     * @return
     */
    @Override
    public Map<String, Object> appPay(PayParam payParam) {
        RechargeRecord rechargeRecord = getRechargeRecord(payParam);
        String payInfo = null;
        try {
            //支付宝
            if (payParam.getType() == null || payParam.getType().equals(PayTypeEnum.ALIPAY.desc())) {
                payInfo = alipayService.rechangeAppPay(rechargeRecord.getOrderNo(), payParam.getPrice());
            }
            //微信支付
            if (payParam.getType() != null && payParam.getType().equals(PayTypeEnum.WXPAY.desc())) {
                WxPayParam wxPayParam = getWxPayParam(payParam, rechargeRecord.getOrderNo(), "APP");
                Map<String, String> map = wxLoginService.appDisposePay(wxPayParam);
                payInfo = JSONObject.toJSONString(map);
            }
        } catch (Exception e) {
            log.info("推广充值app支付异常{}", Arrays.toString(e.getStackTrace()));
            throw new ServiceException("支付异常");
        }
        rechargeRecordMapper.insert(rechargeRecord);
        Map<String, Object> map = new HashMap<>();
        map.put("orderNo", rechargeRecord.getOrderNo());
        map.put("payInfo", payInfo);
        return map;

    }

    /**
     * 获取活动链接
     *
     * @return
     */
    @Override
    public Object getUrl() {
        try {
            String value = configService.getValue(ConfigKey.RECOMMEND_URL);
            return JSONObject.parseObject(value);
        } catch (Exception e) {
            log.error("获取推广url异常{}", e.getLocalizedMessage());
            Map<String, String> map = Maps.newHashMap();
            map.put("tuiUrl", "https://kuaisutest.chengguokj.com/activity/promotionMe");
            return map;
        }
    }

    /**
     * 判断用户是否已经充值
     *
     * @param userId
     * @return
     */
    @Override
    public Boolean isRecharge(Integer userId) {
        List<RechargeRecord> rechargeRecords = rechargeRecordMapper.selectByUserIdAndStatus(userId, 2);
        if (rechargeRecords == null) {
            return false;
        }
        return rechargeRecords.size() >= getRechargeCount();
    }

    private int getRechargeCount() {
        try {
            String value = configService.getValue(ConfigKey.RECHARGE_COUNT);
            return Integer.valueOf(value);
        } catch (Exception e) {
            log.error("获取充值上线异常{}", e.getLocalizedMessage());
            e.printStackTrace();
        }
            return 1;
    }

    private void commissionMessage(Map<String, String> messMap, Integer payAmount) {
        try {
            if (messMap == null || messMap.size() == 0) {
                return;
            }
            String userId = messMap.get("userId");
            //【${phone}】充值${payAmount}元， 成功获取${getAmount}
            Map<String, Object> param = new HashMap<>();
            param.put("phone", messMap.get("phone"));
            param.put("payAmount", FormatUtils.fenToYuan(payAmount));
            String getAmount = messMap.get("getAmount");
            int intAmount = Integer.valueOf(getAmount);
            param.put("getAmount", FormatUtils.fenToYuan(intAmount));
            Map<String, String> map = templateService.commonValue(param, MessageTemplate.COMMISSION);
            int res = noticeService.activieyCreateAndSave(map, Integer.valueOf(userId), MessageNotice.Type.activity_commission.value());
            if (res != 1) {
                log.info("写入佣金消息异常");
            }
        } catch (Exception e) {
            log.error("写入佣金消息异常{}", e.getLocalizedMessage());
            e.printStackTrace();
        }
    }

    private void sendCouponInfo(RechargeRecord rechargeRecord) {
        try {
            List<Probability> probabilities = Lists.newArrayList();
            probabilities.add(new Probability(30, 50, 600));
            probabilities.add(new Probability(60, 100, 370));
            probabilities.add(new Probability(110, 190, 29));
            probabilities.add(new Probability(200, 200, 1));
            Integer lottery = Lottery.lottery(probabilities);
            if (!userCouponService.getRecommendCoupon(rechargeRecord.getUserId(), lottery)) {
                log.warn("获取推广优惠券失败");
            }
        } catch (ServiceException e) {
            log.error("推广获取随机券异常{}", e.getMessage());
        } catch (Exception e) {
            log.error("推广获取随机券异常{}", e.getLocalizedMessage());
            e.printStackTrace();
        }
    }

    private int getRandomIndex(int size) {
        return new Random().nextInt(size);
    }

    /**
     * 从10000中是否获取到8888
     *
     * @return
     */
    private boolean getRandom(Integer bound) {
        int random = new Random().nextInt(bound);
        if (random == 8888) {
            return true;
        } else {
            return false;
        }
    }

    private List<Integer> getTypes() {
        List<Integer> types = new ArrayList<>();
        types.add(CouponConst.typeReduction);//1 优惠券
        types.add(CouponConst.typeVip);//3 vip券
        types.add(CouponConst.typeShare);// 4 分享有礼券
        types.add(CouponConst.free); //5 免单券
        return types;
    }

    private Map<String, String> commission(RechargeRecord rechargeRecord) {
        Map<String, String> map = new HashMap<>();
        try {
            //通过邀请码获取邀请码对应的用户
            UserInfo userInfo = userInfoService.selectUserByCode(rechargeRecord.getInviteId());
            if (userInfo == null) {
                return null;
            }
            //获取佣金比例
            Integer commissionRate = getCommissionRate();
            //获取佣金
            Integer amount = FormatUtils.amountToRate(rechargeRecord.getPayAmount(), commissionRate);
            Boolean isSuccess = overviewService.addAmount(amount, userInfo.getId(), UserBill.Type.COMMSION.value(), UserBill.Type.COMMSION.desc());
            if (!isSuccess) {
                log.info("佣金增加余额失败userId = {}, amount = {}", userInfo.getId(), amount);
            }
            UserInfo orderUser = userInfoService.selectByPrimaryKey(rechargeRecord.getUserId());
            if (orderUser == null) {
                return null;
            }
            map.put("getAmount", String.valueOf(amount));
            map.put("phone", orderUser.getPhone());
            map.put("userId", String.valueOf(userInfo.getId()));
            return map;
        } catch (Exception e) {
            log.error("发放佣金异常{}", e.getLocalizedMessage());
            e.printStackTrace();
        }
        return map;
    }

    private Integer getCommissionRate() {
        Integer rate = 10;
        try {
            String value = configService.getValue(ConfigKey.RECOMMEND);
            JSONObject jsonObject = JSONObject.parseObject(value);
            rate = (Integer) jsonObject.get("rate");
        } catch (Exception e) {
            log.error("获取推广佣金比例异常{}", e.getLocalizedMessage());
            e.printStackTrace();
        }
        return rate;
    }


    private RechargeRecord getRechargeRecord(PayParam payParam) {

        String orderNo = Utility.getOrderNo();
        RechargeRecord rechargeRecord = new RechargeRecord();
        rechargeRecord.setOrderNo(orderNo);
        rechargeRecord.setPayAmount(payParam.getPrice());
        rechargeRecord.setType(RechangeRecordEnum.TEN.value());
        rechargeRecord.setOrderDesc(RechangeRecordEnum.TEN.desc());
        rechargeRecord.setUserId(payParam.getUserId());
        rechargeRecord.setStatus(RechargeRecordStatus.prePay);
        rechargeRecord.setInviteId(payParam.getInviteId());
        rechargeRecord.setActivityId(payParam.getActivityId());
        //支付方式，0微信，1支付宝，4小程序，5公众号
        if (PayTypeEnum.ALIPAY.desc().equals(payParam.getType())) {
            rechargeRecord.setPaymentMethod(PayTypeEnum.ALIPAY.value());
        }
        if (PayTypeEnum.WXPAY.desc().equals(payParam.getType())) {
            rechargeRecord.setPaymentMethod(PayTypeEnum.WXPAY.value());
        }
        if (PayTypeEnum.XCX.desc().equals(payParam.getType())) {
            rechargeRecord.setPaymentMethod(PayTypeEnum.XCX.value());
        }
        if (PayTypeEnum.GZH.desc().equals(payParam.getType())) {
            rechargeRecord.setPaymentMethod(PayTypeEnum.GZH.value());
        }
        return rechargeRecord;
    }
}
